#!/usr/bin/env python
import httplib
import pybonjour
import select

class Timeout(Exception):
    def __str__(self):
        print("Operation Timeout")

class InvalidParam(Exception):
    def __init__(self, param):
        self.p = param
    def __str__(self):
        print("Parameters are invalid: {0}".format(self.p))

class ErrorResponse(Exception):
    def __init__(self, code):
        self.status = code
    def __str__(self):
        print("Unacceptable http status code: {0}".format(self.status))

class Detector(object):
    def __init__(self, regtype=None, timeout=5):
        self._timeout = timeout
        self._regtype = regtype
        self.alive = 0
        self.port = -1
        self.hostname = None

    def discover(self, regtype=None):
        if self.alive == -1:
            return
        if isinstance(regtype, str):
            self._regtype = regtype
        if not self._regtype:
            return
        self.alive = -1 #running
        print('start to discover: {0}'.format(self._regtype))
        browse_sdRef = pybonjour.DNSServiceBrowse(regtype = self._regtype, callBack = self._browse_callback)
        ready = select.select([browse_sdRef], [], [], self._timeout)
        if browse_sdRef in ready[0]:
            pybonjour.DNSServiceProcessResult(browse_sdRef)
            browse_sdRef.close()
            return
        # timeout
        self.alive = 0
        browse_sdRef.close()
        raise Timeout

    def _browse_callback(self, sdRef, flags, interfaceIndex, errorCode, serviceName, regtype, replyDomain):
        if errorCode != pybonjour.kDNSServiceErr_NoError:
            self.alive = 0
            return
        if not (flags & pybonjour.kDNSServiceFlagsAdd):
            self.alive = 0
            return
        resolve_sdRef = pybonjour.DNSServiceResolve(0,
                                      interfaceIndex,
                                      serviceName,
                                      regtype,
                                      replyDomain,
                                      self._resolve_callback)
        ready = select.select([resolve_sdRef], [], [], self._timeout)
        if resolve_sdRef in ready[0]:
            pybonjour.DNSServiceProcessResult(resolve_sdRef)
            resolve_sdRef.close()
            return
        # timeout
        self.alive = 0
        resolve_sdRef.close()
        raise Timeout

    def _resolve_callback(self, sdRef, flags, interfaceIndex, errorCode, fullname, hosttarget, port, txtRecord):
        if errorCode == pybonjour.kDNSServiceErr_NoError:
            self.alive = 1
            self.port = port
            self.hostname = hosttarget
            print 'Resolved service:'
            print '  fullname   =', fullname
            print '  hosttarget =', hosttarget
            print '  port       =', port
        else:
            self.alive = 0

    def fetch(self, style='html'):
        if self.alive != 1:
            return (False, None)
        if not isinstance(style, str):
            raise InvalidParam(style)
        style = style.lower();
        if style != 'html' and style != 'json':
            raise InvalidParam(style)
        conn = httplib.HTTPConnection(self.hostname, self.port)
        conn.request('GET', '/{0}/report'.format(style))
        resp = conn.getresponse()
        status = resp.status
        if status == 204:
            conn.close()
            return (False, None)
        elif status == 200:
            data = resp.read()
            conn.close()
            return (True, data)
        conn.close()
        raise ErrorResponse(status)

if __name__=='__main__':
    test = Detector("_x-UiTruncation._tcp")
    test.discover()
    if test.alive == 1:
        result, data = test.fetch();
        if result:
            with open('aaaa.html', 'w') as f:
                    f.write(data)
        #result, data = test.fetch('json')
        #import json
        #if result:
        #    job = json.loads(data)
        #    print(job['appname'])
        #    with open('jjj.json', 'w') as f:
        #        f.write(data)
